FALSE Warning messages:
FALSE 1: replacing previous import ‘acs::combine’ by ‘dplyr::combine’ when loading ‘miscgis’
FALSE 2: replacing previous import ‘acs::span’ by ‘htmltools::span’ when loading ‘miscgis’
Introduction
The US Census provides invaluable information about American communities. The datasets provided by the Census encompas many disparate topics, comprehensively cover the entire US population, and are freely available to download. However, there are some barriers to using these data sets. When dealing with small geographies like a neighborhood, the statistical uncertainty may be high because the information comes from a small sample of the population. This complicates common data processing steps like combining or calculating the proportion of given indicator. Additionally, because census tract boundaries are subject to change every ten years, datasets must be normalized to account for this change before any comparative analysis can begin. Lastly, the census datasets represent information that is specific to a given geography (e.g. people in Tukwila, or households in King County) and are, therefore, spatial in nature. Spatial data, from the Census or other sources, present their own challenges that researchers must address in their choice of methods.
This analysis addresses these challenges by leveraging the capabilities of R, an opensource statistical programming language. While other software exists for working with Census data, there are several R-based tools that can be combined together efficiently and effectively. The method for downloading, organizing, and processing the data are summarized in the following steps:
- Define census geographies of interest
- Identify relevant tables from American Community Survey
- Download tables using the
acs R package
- Normalize the pre-2010 dataset using Brown University’s Longitudinal Tract Database
- Approximate the COO site communities by combining census tracts
ACS Geographies
There are many ways to collect US Census data, but this method uses the R package called acs to extract data with the official US Census API. This method is efficient, reproducible, and allows users to download census tables for a group of dissimilar geographies. To learn more about this, see the acs package documentation.
This analysis uses the following three types of census geographies:
- Counties (King)
- County subdivisions (Seattle CCD)
- Census tracts (all tracts within King County)
ACS Tables
The following tables from the American Community Survey (ACS) are used to created indicators in this assessment
| B03002 |
HISPANIC OR LATINO ORIGIN BY RACE |
Total population |
| B15002 |
SEX BY EDUCATIONAL ATTAINMENT FOR THE POPULATION 25 YEARS AND OVER |
Population 25 years and over |
| B19001 |
HOUSEHOLD INCOME IN THE PAST 12 MONTHS (IN 2015 INFLATION-ADJUSTED DOLLARS) |
Households |
| B25033 |
TOTAL POPULATION IN OCCUPIED HOUSING UNITS BY TENURE BY UNITS IN STRUCTURE |
Total population in occupied housing units |
Prior to normalization, the tables are stored in two separate dataframes: one for the 2005-2009 data, and another for the 2011-2015 data:
Census Tables, 2005-2009
Simple feature collection with 375 features and 92 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -122.5279 ymin: 47.08446 xmax: -121.0657 ymax: 47.78033
epsg (SRID): NA
proj4string: NA
Census Tables, 2011-2015
Simple feature collection with 400 features and 92 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -122.5279 ymin: 47.08446 xmax: -121.0657 ymax: 47.78033
epsg (SRID): NA
proj4string: NA
Data Structure: acs objects distributed in sf objects
In this method, each row contains a different census geography and each column contains a single column of a single census table. For instance, column B03002_003 contains the third column of the ‘Hispanic or Latino, By Race’ table, which contains the estimate of people who identify as “Not Hispanic or Latino: White alone”:
Simple feature collection with 1 feature and 4 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -122.5279 ymin: 47.08446 xmax: -121.0657 ymax: 47.78033
epsg (SRID): NA
proj4string: NA
Each “cell” of the dataframe contains a single acs-class object, which itself contains a set of metadata including the estimate value, standard error, geographic identifier, and other useful information:
ACS DATA:
2005 -- 2009 ;
Estimates w/90% confidence intervals;
for different intervals, see confint()
B03002_003
Census Tract 1, King County, Washington 3596 +/- 358
Formal class 'acs' [package "acs"] with 9 slots
..@ endyear : int 2009
..@ span : int 5
..@ geography :'data.frame': 1 obs. of 5 variables:
.. ..$ NAME : chr "Census Tract 1, King County, Washington"
.. ..$ state : int 53
.. ..$ county : chr "33"
.. ..$ countysubdivision: chr NA
.. ..$ tract : chr "000100"
..@ acs.colnames : chr "B03002_003"
..@ modified : logi TRUE
..@ acs.units : Factor w/ 5 levels "count","dollars",..: NA
..@ currency.year : int 2009
..@ estimate : num [1, 1] 3596
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : chr "Census Tract 1, King County, Washington"
.. .. ..$ : chr "B03002_003"
..@ standard.error: num [1, 1] 218
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : chr "Census Tract 1, King County, Washington"
.. .. ..$ : chr "B03002_003"
Storing acs objects in a simple feature dataframe is unconventional but it follows a general principle of computing: don’t repeat yourself (DRY). The dataframe structure keeps related acs objects and geometries together, yielding benefits when the time comes to operate on the data.
For example, if census tracts need to be normalized before temporal comparison (as is the case in this project), that process can occur in a single, comprehensive step rather than individually for each census table. This efficiency gain is particularly important if census tables are added or removed, which may occur fequently in the exploratory phase of an analysis.
Normalized pre-2010 Data
Ultimately the ACS data will be combined into a single simple feature object, but before that can happen the pre-2010 must be normalized. The LTDB 2000-2010 Crosswalk file is a tabular tool that clarifies which tracts change from decade to decade, what type of change occurred (e.g., consolidation, split, many-to-many, none), and what weighting metric should be used to inpute the pre-2010 values. This information makes it possible to conduct meaningful temporal analysis on tracts whose boundaries changed between the two decades. More information regarding the normalization method can be found at the Longitudinal Tract Database website.
Once the pre-2010 data has been normalized, the data for the two observations periods can be combined into a single dataframe:
Simple feature collection with 399 features and 176 fields
geometry type: MULTIPOLYGON
dimension: XY
bbox: xmin: -122.5279 ymin: 47.08446 xmax: -121.0657 ymax: 47.78033
epsg (SRID): NA
proj4string: NA
LS0tDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogIHBkZl9kb2N1bWVudDoNCiAgICBrZWVwX3RleDogeWVzDQphbHdheXNfYWxsb3dfaHRtbDogeWVzDQotLS0NCg0KYGBge3IgY2Vuc3VzLWFjcy1zZXR1cCwgZWNobyA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsY29tbWVudD1GQUxTRX0NCmxpYnJhcnkocGx5cikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHJwcm9qcm9vdCkNCmxpYnJhcnkocmdkYWwpDQpsaWJyYXJ5KHNwKQ0KbGlicmFyeShyZ2VvcykNCmxpYnJhcnkodGlncmlzKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGRvd25sb2FkZXIpDQpsaWJyYXJ5KHdlYnNob3QpDQpsaWJyYXJ5KGh0bWx0b29scykNCmxpYnJhcnkoZ3Bsb3RzKQ0KbGlicmFyeShnZ21hcCkNCmxpYnJhcnkoc2hpbnkpDQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGFjcykNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KG1pc2NnaXMpDQpsaWJyYXJ5KG9wZXJhdG9yLnRvb2xzKQ0KbGlicmFyeShsZWFmbGV0LmV4dHJhcykNCmxpYnJhcnkodmlyaWRpc0xpdGUpDQpsaWJyYXJ5KHNmKQ0Kcm9vdCA8LSBycHJvanJvb3Q6OmlzX3JzdHVkaW9fcHJvamVjdA0Kcm9vdF9maWxlIDwtIHJvb3QkbWFrZV9maXhfZmlsZSgpDQpvcHRzX2NodW5rJHNldChlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjb21tZW50PUZBTFNFKQ0KDQpgYGANCg0KIyMjIEludHJvZHVjdGlvbiB7LX0NCg0KVGhlIFVTIENlbnN1cyBwcm92aWRlcyBpbnZhbHVhYmxlIGluZm9ybWF0aW9uIGFib3V0IEFtZXJpY2FuIGNvbW11bml0aWVzLiBUaGUgZGF0YXNldHMgcHJvdmlkZWQgYnkgdGhlIENlbnN1cyBlbmNvbXBhcyBtYW55IGRpc3BhcmF0ZSB0b3BpY3MsIGNvbXByZWhlbnNpdmVseSBjb3ZlciB0aGUgZW50aXJlIFVTIHBvcHVsYXRpb24sIGFuZCBhcmUgZnJlZWx5IGF2YWlsYWJsZSB0byBkb3dubG9hZC4gSG93ZXZlciwgdGhlcmUgYXJlIHNvbWUgYmFycmllcnMgdG8gdXNpbmcgdGhlc2UgZGF0YSBzZXRzLiBXaGVuIGRlYWxpbmcgd2l0aCBzbWFsbCBnZW9ncmFwaGllcyBsaWtlIGEgbmVpZ2hib3Job29kLCB0aGUgc3RhdGlzdGljYWwgdW5jZXJ0YWludHkgbWF5IGJlIGhpZ2ggYmVjYXVzZSB0aGUgaW5mb3JtYXRpb24gY29tZXMgZnJvbSBhIHNtYWxsIHNhbXBsZSBvZiB0aGUgcG9wdWxhdGlvbi4gVGhpcyBjb21wbGljYXRlcyBjb21tb24gZGF0YSBwcm9jZXNzaW5nIHN0ZXBzIGxpa2UgY29tYmluaW5nIG9yIGNhbGN1bGF0aW5nIHRoZSBwcm9wb3J0aW9uIG9mIGdpdmVuIGluZGljYXRvci4gQWRkaXRpb25hbGx5LCBiZWNhdXNlIGNlbnN1cyB0cmFjdCBib3VuZGFyaWVzIGFyZSBzdWJqZWN0IHRvIGNoYW5nZSBldmVyeSB0ZW4geWVhcnMsIGRhdGFzZXRzIG11c3QgYmUgbm9ybWFsaXplZCB0byBhY2NvdW50IGZvciB0aGlzIGNoYW5nZSBiZWZvcmUgYW55IGNvbXBhcmF0aXZlIGFuYWx5c2lzIGNhbiBiZWdpbi4gTGFzdGx5LCB0aGUgY2Vuc3VzIGRhdGFzZXRzIHJlcHJlc2VudCBpbmZvcm1hdGlvbiB0aGF0IGlzIHNwZWNpZmljIHRvIGEgZ2l2ZW4gZ2VvZ3JhcGh5IChlLmcuIHBlb3BsZSBpbiBUdWt3aWxhLCBvciBob3VzZWhvbGRzIGluIEtpbmcgQ291bnR5KSBhbmQgYXJlLCB0aGVyZWZvcmUsIF9zcGF0aWFsXyBpbiBuYXR1cmUuIFNwYXRpYWwgZGF0YSwgZnJvbSB0aGUgQ2Vuc3VzIG9yIG90aGVyIHNvdXJjZXMsIHByZXNlbnQgdGhlaXIgb3duIGNoYWxsZW5nZXMgdGhhdCByZXNlYXJjaGVycyBtdXN0IGFkZHJlc3MgaW4gdGhlaXIgY2hvaWNlIG9mIG1ldGhvZHMuDQoNClRoaXMgYW5hbHlzaXMgYWRkcmVzc2VzIHRoZXNlIGNoYWxsZW5nZXMgYnkgbGV2ZXJhZ2luZyB0aGUgY2FwYWJpbGl0aWVzIG9mIFIsIGFuIG9wZW5zb3VyY2Ugc3RhdGlzdGljYWwgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UuIFdoaWxlIG90aGVyIHNvZnR3YXJlIGV4aXN0cyBmb3Igd29ya2luZyB3aXRoIENlbnN1cyBkYXRhLCB0aGVyZSBhcmUgc2V2ZXJhbCBSLWJhc2VkIHRvb2xzIHRoYXQgY2FuIGJlIGNvbWJpbmVkIHRvZ2V0aGVyIGVmZmljaWVudGx5IGFuZCBlZmZlY3RpdmVseS4gVGhlIG1ldGhvZCBmb3IgZG93bmxvYWRpbmcsIG9yZ2FuaXppbmcsIGFuZCBwcm9jZXNzaW5nIHRoZSBkYXRhIGFyZSBzdW1tYXJpemVkIGluIHRoZSBmb2xsb3dpbmcgc3RlcHM6DQoNCiAgMS4gRGVmaW5lIGNlbnN1cyBnZW9ncmFwaGllcyBvZiBpbnRlcmVzdA0KICAyLiBJZGVudGlmeSByZWxldmFudCB0YWJsZXMgZnJvbSBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5DQogIDMuIERvd25sb2FkIHRhYmxlcyB1c2luZyB0aGUgYGFjc2AgUiBwYWNrYWdlDQogIDQuIE5vcm1hbGl6ZSB0aGUgcHJlLTIwMTAgZGF0YXNldCB1c2luZyBCcm93biBVbml2ZXJzaXR5J3MgW0xvbmdpdHVkaW5hbCBUcmFjdCBEYXRhYmFzZV0oaHR0cDovL3d3dy5zNC5icm93bi5lZHUvdXMyMDEwL1Jlc2VhcmNoZXIvTFREQi5odG0pDQogIDUuIEFwcHJveGltYXRlIHRoZSBDT08gc2l0ZSBjb21tdW5pdGllcyBieSBjb21iaW5pbmcgY2Vuc3VzIHRyYWN0cw0KDQojIyMgQUNTIEdlb2dyYXBoaWVzIHstfQ0KDQpUaGVyZSBhcmUgbWFueSB3YXlzIHRvIGNvbGxlY3QgVVMgQ2Vuc3VzIGRhdGEsIGJ1dCB0aGlzIG1ldGhvZCB1c2VzIHRoZSBgUmAgcGFja2FnZSBjYWxsZWQgYGFjc2AgdG8gZXh0cmFjdCBkYXRhIHdpdGggdGhlIG9mZmljaWFsIFVTIENlbnN1cyBBUEkuIFRoaXMgbWV0aG9kIGlzIGVmZmljaWVudCwgcmVwcm9kdWNpYmxlLCBhbmQgYWxsb3dzIHVzZXJzIHRvIGRvd25sb2FkIGNlbnN1cyB0YWJsZXMgZm9yIGEgZ3JvdXAgb2YgZGlzc2ltaWxhciBnZW9ncmFwaGllcy4gVG8gbGVhcm4gbW9yZSBhYm91dCB0aGlzLCBzZWUgdGhlIGBhY3NgIHBhY2thZ2UgW2RvY3VtZW50YXRpb25dKGh0dHA6Ly9lZ2xlbm4uc2NyaXB0cy5taXQuZWR1L2NpdHlzdGF0ZS93cC1jb250ZW50L3VwbG9hZHMvMjAxMy8wNi93cGlkLXdvcmtpbmdfd2l0aF9hY3NfUjMucGRmKS4NCg0KVGhpcyBhbmFseXNpcyB1c2VzIHRoZSBmb2xsb3dpbmcgdGhyZWUgdHlwZXMgb2YgY2Vuc3VzIGdlb2dyYXBoaWVzOg0KDQogICogQ291bnRpZXMgKEtpbmcpDQogICogQ291bnR5IHN1YmRpdmlzaW9ucyAoU2VhdHRsZSBDQ0QpDQogICogQ2Vuc3VzIHRyYWN0cyAoYWxsIHRyYWN0cyB3aXRoaW4gS2luZyBDb3VudHkpDQogIA0KYGBge3IgY2Vuc3VzLWFjcy1nZW9zZXR9DQoNCiMgU2F2ZSBhbiBhY3Mgb2JqZWN0DQoNCmlmKCFmaWxlLmV4aXN0cyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vY29vLWdlb3NldC1hY3MucmRzJykpKXsNCiAgICAgICAgYygNCiAgICAgICAgYWNzOjpnZW8ubWFrZShzdGF0ZSA9ICJXQSIsY291bnR5ID0gIktpbmciKSwNCiAgICAgICAgYWNzOjpnZW8ubWFrZShzdGF0ZSA9ICJXQSIsIGNvdW50eSA9ICJLaW5nIixjb3VudHkuc3ViZGl2aXNpb24gPSAiU2VhdHRsZSBDQ0QiKSwNCiAgICAgICAgYWNzOjpnZW8ubWFrZShzdGF0ZSA9ICJXQSIsY291bnR5ID0gIktpbmciLCB0cmFjdCA9ICcqJykNCikgJT4lDQogICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vY29vLWdlb3NldC1hY3MucmRzJykpDQp9DQoNCg0KYGBgDQoNCiMjIyBBQ1MgVGFibGVzIHstfQ0KDQpUaGUgZm9sbG93aW5nIHRhYmxlcyBmcm9tIHRoZSBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IChBQ1MpIGFyZSB1c2VkIHRvIGNyZWF0ZWQgaW5kaWNhdG9ycyBpbiB0aGlzIGFzc2Vzc21lbnQNCg0KYGBge3IgY2Vuc3VzLWFjcy10YWJsZXMtcHJldmlld30NCg0KdHJpYmJsZSgNCiAgICAgICAgfiAnVGFibGUgTmFtZScsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiAnVG9waWMnLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH4gJ1VuaXZlcnNlJywNCiAgICAgICAgICAgICAgJ0IwMzAwMicsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdISVNQQU5JQyBPUiBMQVRJTk8gT1JJR0lOIEJZIFJBQ0UnLCAgICAgICAgICAgICAgICAgICAgICAgICAgICdUb3RhbCBwb3B1bGF0aW9uJywNCiAgICAgICAgICAgICAgJ0IxNTAwMicsICAgICAgICAgICdTRVggQlkgRURVQ0FUSU9OQUwgQVRUQUlOTUVOVCBGT1IgVEhFIFBPUFVMQVRJT04gMjUgWUVBUlMgQU5EIE9WRVInLCAgICAgICAgICAgICAgICdQb3B1bGF0aW9uIDI1IHllYXJzIGFuZCBvdmVyJywNCiAgICAgICAgICAgICAgJ0IxOTAwMScsICdIT1VTRUhPTEQgSU5DT01FIElOIFRIRSBQQVNUIDEyIE1PTlRIUyAoSU4gMjAxNSBJTkZMQVRJT04tQURKVVNURUQgRE9MTEFSUyknLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdIb3VzZWhvbGRzJywNCiAgICAgICAgICAgICAgJ0IyNTAzMycsICAnVE9UQUwgUE9QVUxBVElPTiBJTiBPQ0NVUElFRCBIT1VTSU5HIFVOSVRTIEJZIFRFTlVSRSBCWSBVTklUUyBJTiBTVFJVQ1RVUkUnLCAnVG90YWwgcG9wdWxhdGlvbiBpbiBvY2N1cGllZCBob3VzaW5nIHVuaXRzJw0KICAgICAgICAgICAgICANCikgJT4lIGthYmxlKCkNCg0KYGBgDQoNCg0KUHJpb3IgdG8gbm9ybWFsaXphdGlvbiwgdGhlIHRhYmxlcyBhcmUgc3RvcmVkIGluIHR3byBzZXBhcmF0ZSBkYXRhZnJhbWVzOiBvbmUgZm9yIHRoZSAyMDA1LTIwMDkgZGF0YSwgYW5kIGFub3RoZXIgZm9yIHRoZSAyMDExLTIwMTUgZGF0YToNCg0KYGBge3IgY2Vuc3VzLWdldC10YWJsZXN9DQoNCiMgQSBmdW5jdGlvbiB0aGF0IGNvbWJpbmVzIHBhaXJzIG9mIEFDUyB0YWJsZSBudW1iZXJzIHdpdGggZW5keWVhcnMsDQojIHRoZW4gZG93bmxvYWRzIHRoZSBjb3JyZXNwb25kaW5nIGRhdGFzZXRzIGFuZCBzdG9yZXMgdGhlbSBpbiBhIHRpYmJsZQ0KDQpmZXRjaF9hbGxfYWNzIDwtIGZ1bmN0aW9uKHRhYmxlcyxlbmR5ZWFycyxnZW9ncmFwaHkpew0KICAgICAgICANCiAgICAgICAgZmV0Y2hfY2FsbHMgPC0gDQogICAgICAgICAgICAgICAgY3Jvc3NpbmcoJ3RhYmxlLm51bWJlcicgPSB0YWJsZXMsICdlbmR5ZWFyJyA9IGVuZHllYXJzKSAlPiUgDQogICAgICAgICAgICAgICAgcHVycnI6Om1hcF9yb3dzKGxpc3QsIC50byA9ICdSRVNVTFQnKSAlPiUgDQogICAgICAgICAgICAgICAgZXh0cmFjdDIoJ1JFU1VMVCcpDQogICAgICAgIA0KICAgICAgICBhY3NfdGliYmxlIDwtIA0KICAgICAgICAgICAgICAgIGZldGNoX2NhbGxzICU+JSANCiAgICAgICAgICAgICAgICBtYXAoDQogICAgICAgICAgICAgICAgICAgICAgICAuZiA9IH4gYWNzLmZldGNoKGVuZHllYXIgPSBleHRyYWN0MigueCwnZW5keWVhcicpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWJsZS5udW1iZXIgPSBleHRyYWN0MigueCwndGFibGUubnVtYmVyJyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwYW4gPSA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9ncmFwaHkgPSBnZW9ncmFwaHkpDQogICAgICAgICAgICAgICAgKSAlPiUgDQogICAgICAgICAgICAgICAgdGliYmxlKCdFTkRZRUFSJyA9IG1hcF9pbnQoey59LGVuZHllYXIpKSAlPiUgDQogICAgICAgICAgICAgICAgc2V0X2NvbG5hbWVzKGMoJ0FDUycsJ0VORFlFQVInKSkNCiAgICAgICAgDQogICAgICAgIHJldHVybihhY3NfdGliYmxlKQ0KfQ0KDQp0YWJsZXMgPC0gYyggJ0IwMzAwMicsICdCMTUwMDInLCAnQjE5MDAxJywgJ0IyNTAzMycpDQoNCmVuZHllYXJzIDwtIGMoIDIwMDksIDIwMTUpDQoNCmNvb19nZW9fYWNzIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnMS1kYXRhLzQtaW50ZXJpbS9jb28tZ2Vvc2V0LWFjcy5yZHMnKSkNCg0KIyBFeGVjdXRlIHRoZSBmdW5jdGlvbg0KDQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtcmF3LWRhdGEucmRzJykpKXsNCiAgICAgICAgZmV0Y2hfYWxsX2Fjcyh0YWJsZXMsZW5keWVhcnMsY29vX2dlb19hY3MpICU+JSANCiAgICAgICAgICAgICAgICB3cml0ZV9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtcmF3LWRhdGEucmRzJykpDQp9DQoNCmFjc190aWJibGUgPC0gcmVhZF9yZHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtcmF3LWRhdGEucmRzJykpDQoNCg0KIyBBIGZ1bmN0aW9uIHRvIG1ha2UgdGFibGUgY29sdW1uIG5hbWUgZ3VpZGUgDQojIE5vdGU6IHRoaXMgd2lsbCBiZSB1c2VmdWwgbGF0ZXIgaW4gdGhlIGFuYWx5c2lzDQojICh3aGVuIHRoZSB2YXJpYWJsZSBjb2x1bW5zIGFyZSBjcmVhdGVkKQ0KDQptYWtlX2NvbG5hbWVfZ3VpZGUgPC0gZnVuY3Rpb24odGFibGVzLGVuZHllYXJzKXsNCiAgICAgICAgDQogICAgICAgIGZldGNoX2NhbGxzIDwtIA0KICAgICAgICAgICAgICAgIGNyb3NzaW5nKCd0YWJsZS5udW1iZXInID0gdGFibGVzLCAnZW5keWVhcicgPSBlbmR5ZWFycywgJ2NvbC5uYW1lcycgPSBjKCdhdXRvJywncHJldHR5JykpICU+JSANCiAgICAgICAgICAgICAgICBwdXJycjo6bWFwX3Jvd3MobGlzdCwgLnRvID0gJ1JFU1VMVCcpICU+JSANCiAgICAgICAgICAgICAgICBleHRyYWN0MignUkVTVUxUJykNCiAgICAgICAgDQogICAgICAgIGFjc190aWJibGUgPC0gDQogICAgICAgICAgICAgICAgZmV0Y2hfY2FsbHMgJT4lIA0KICAgICAgICAgICAgICAgIG1hcCgNCiAgICAgICAgICAgICAgICAgICAgICAgIC5mID0gfiBhY3MuZmV0Y2goZW5keWVhciA9IGV4dHJhY3QyKC54LCdlbmR5ZWFyJyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhYmxlLm51bWJlciA9IGV4dHJhY3QyKC54LCd0YWJsZS5udW1iZXInKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sLm5hbWVzID0gZXh0cmFjdDIoLngsJ2NvbC5uYW1lcycpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGFuID0gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvZ3JhcGh5ID0gYWNzOjpnZW8ubWFrZSh1cyA9IFRSVUUpKQ0KICAgICAgICAgICAgICAgICkgDQogICAgICAgIA0KICAgICAgICBhY3NfdGliYmxlICU+JSANCiAgICAgICAgICAgICAgICB0aWJibGUoJ1RBQkxFJyA9IG1hcCh0YWJsZXMscmVwLDQpICU+JSBmbGF0dGVuX2NocigpLA0KICAgICAgICAgICAgICAgICAgICAgICAnRU5EWUVBUicgPSBtYXBfaW50KHsufSxlbmR5ZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgJ0NPTE5BTUUnID0gbWFwKHsufSxhY3MuY29sbmFtZXMpLA0KICAgICAgICAgICAgICAgICAgICAgICAnQ09MVFlQRScgPSByZXAoYygnVEVSU0UnLCdQUkVUVFknKSxsZW5ndGgoey59KS8yKSkgJT4lIA0KICAgICAgICAgICAgICAgc3ByZWFkKENPTFRZUEUsQ09MTkFNRSkgJT4lIA0KICAgICAgICAgICAgICAgdW5uZXN0KFRFUlNFLFBSRVRUWSkNCiAgICAgICAgICAgICAgIA0KICAgICAgICANCn0NCg0KIyBFeGVjdXRlIHRoZSBmdW5jdGlvbg0KDQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcuLzEtZGF0YS80LWludGVyaW0vY29vLWFjcy1jb2xuYW1lcy5yZHMnKSkpew0KICAgICAgIG1ha2VfY29sbmFtZV9ndWlkZSh0YWJsZXMsZW5keWVhcnMpICU+JSANCiAgICAgICAgICAgICAgICB3cml0ZV9yZHMocm9vdF9maWxlKCcuLzEtZGF0YS80LWludGVyaW0vY29vLWFjcy1jb2xuYW1lcy5yZHMnKSkNCn0NCg0KDQojIEZ1bmN0aW9ucyBmb3Igd29ya2luZyB3aXRoIGFjcyBvYmplY3RzIHRoYXQgYXJlIHN0b3JlZCBpbiB0aWJibGVzDQoNCmdldF9hY3NfY29sIDwtIGZ1bmN0aW9uKGFjc19saXN0LGFjc19mdW4sY29sKXsNCiAgICAgICAgYWNzX2xpc3QgJT4lIHVubGlzdCAlPiUgYWNzX2Z1bigpICU+JSBleHRyYWN0Mihjb2wpDQp9DQoNCmdldF9nZW9nIDwtIGZ1bmN0aW9uKGFjcyl7DQogICAgICAgIGFjcyAlPiUgDQogICAgICAgICAgICAgICAgZ2VvZ3JhcGh5KCkgJT4lIA0KICAgICAgICAgICAgICAgIGZsYXR0ZW4oKSAlPiUgDQogICAgICAgICAgICAgICAgbWFwKC5mID0gfiAhaXMubmEoLngpKSAlPiUgDQogICAgICAgICAgICAgICAgcmV2ICU+JSANCiAgICAgICAgICAgICAgICB0aWJibGUoJ0dFT0cnID0gbmFtZXMoLiksDQogICAgICAgICAgICAgICAgICAgICAgICdMR0wnID0gdW5saXN0KC4pKSAlPiUgDQogICAgICAgICAgICAgICAgc2VsZWN0KEdFT0csTEdMKSAlPiUgDQogICAgICAgICAgICAgICAgZmlsdGVyKExHTCkgJT4lIA0KICAgICAgICAgICAgICAgIHNsaWNlKDEpICU+JSANCiAgICAgICAgICAgICAgICBleHRyYWN0MignR0VPRycpICU+JSANCiAgICAgICAgICAgICAgICBpZl9lbHNlKC4gJWluJSAnY291bnR5c3ViZGl2aXNpb24nLA0KICAgICAgICAgICAgICAgICAgICAgICAgJ2NvdW50eSBzdWJkaXZpc2lvbicsDQogICAgICAgICAgICAgICAgICAgICAgICAuKQ0KfQ0KDQoNCmRpc3RyaWJ1dGVfYWNzIDwtIGZ1bmN0aW9uKGFjcyl7DQogICAgICAgICMgYnJvd3NlcigpDQogICAgICAgDQogICAgICAgIGlmKGNsYXNzKGFjcykgJWluJSAiYWNzIil7DQogICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgYWNzICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgYXBwbHkoMixmdW5jdGlvbih4KXthcHBseSh4LDEsbGlzdCkgJT4lIGFzX3RpYmJsZX0pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgc2V0X2NvbG5hbWVzKGFjcy5jb2xuYW1lcyhhY3MpKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoTkFNRSA9IG1hcF9jaHIoLnggPSB7ZXh0cmFjdDIoLiwxKX0sLmYgPSB+IGdldF9hY3NfY29sKC54LCBnZW9ncmFwaHksJ05BTUUnKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR0VPSUQ2ID0gbWFwX2NocigueCA9IHtleHRyYWN0MiguLDEpfSwuZiA9IH4gZ2V0X2Fjc19jb2woLngsIGdlb2dyYXBoeSwndHJhY3QnKSkpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChOQU1FLEdFT0lENixldmVyeXRoaW5nKCkpDQogICAgICAgICAgICAgICAgDQogICAgICAgIH1lbHNlew0KICAgICAgICAgICAgICAgIGFjcyAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBleHRyYWN0MigxKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBhcHBseSgyLGZ1bmN0aW9uKHgpe2FwcGx5KHgsMSxsaXN0KSAlPiUgYXNfdGliYmxlfSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBzZXRfY29sbmFtZXMoYWNzLmNvbG5hbWVzKGFjcykpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShHRU9JRDYgPSBtYXBfY2hyKC54ID0ge2V4dHJhY3QyKC4sMSl9LC5mID0gfiB1bmxpc3QoLngpICU+JSBnZW9ncmFwaHkoKSAlPiUgZXh0cmFjdDIoJ3RyYWN0JykpKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoR0VPSUQ2LGV2ZXJ5dGhpbmcoKSkNCiAgICAgICAgfQ0KICAgICAgICANCiAgICAgICAgDQp9DQoNCiMgU2VwYXJhdGUgdGhlIGFjcyBvYmplY3RzIGJ5IHllYXINCiMgYW5kIGpvaW4gdG8gdGhlIHNpbXBsZSBmZWF0dXJlIG9iamVjdHMNCg0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtMjAwOS1zZi5yZHMnKSkpew0KICAgICAgICANCiAgICAgICAgIyBMb2FkIHRoZSBzZiBvYmplY3QNCiAgICAgICAgDQogICAgICAgIGNvb19nZW9tc18yMDA5X3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtMjAwOS1nZW9tcy1zZi5yZHMnKSkNCiAgICAgICAgDQogICAgICAgICMgRGlzdHJpYnV0ZSB0aGUgYWNzIGludG8gYSBkYXRhZnJhbWUsDQogICAgICAgICMgam9pbiBpdCB0byB0aGUgc2Ygb2JqZWN0LA0KICAgICAgICAjIGFkZCBhbiAnRU5EWUVBUicgdmFyaWFibGUNCiAgICAgICAgIyBzYXZlIGFzIGFuIHNmIG9iamVjdA0KICAgICAgICANCiAgICAgICAgYWNzX3RpYmJsZSAlPiUgDQogICAgICAgICAgICAgICAgZmlsdGVyKEVORFlFQVIgJWluJSAyMDA5KSAlPiUgDQogICAgICAgICAgICAgICAgZXh0cmFjdDIoJ0FDUycpICU+JSANCiAgICAgICAgICAgICAgICBtYXAoZGlzdHJpYnV0ZV9hY3MpICU+JSANCiAgICAgICAgICAgICAgICByZWR1Y2UobGVmdF9qb2luLCBieSA9IGMoIk5BTUUiLCAiR0VPSUQ2IikpICU+JSANCiAgICAgICAgICAgICAgICByZW5hbWUoTkFNRV9GVUxMID0gTkFNRSkgJT4lIA0KICAgICAgICAgICAgICAgIGxlZnRfam9pbihjb29fZ2VvbXNfMjAwOV9zZiwgYnkgPSBjKCdHRU9JRDYnLCdOQU1FX0ZVTEwnKSkgJT4lDQogICAgICAgICAgICAgICAgbXV0YXRlKEVORFlFQVIgPSBtYXBfaW50KEIwMzAwMl8wMDEsIGVuZHllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICBHRU9HUkFQSFkgPSBtYXBfY2hyKEIwMzAwMl8wMDEsIGdldF9nZW9nKSkgJT4lIA0KICAgICAgICAgICAgICAgIHNlbGVjdChOQU1FLE5BTUVfRlVMTCxHRU9JRDYsR0VPR1JBUEhZLFNFQUNDRF9MR0wsRU5EWUVBUixldmVyeXRoaW5nKCksZ2VvbWV0cnkpICU+JSANCiAgICAgICAgICAgICAgICBzdF9hc19zZigpICU+JSANCiAgICAgICAgICAgICAgICB3cml0ZV9yZHMocm9vdF9maWxlKCcuLzEtZGF0YS80LWludGVyaW0vY29vLWFjcy0yMDA5LXNmLnJkcycpKQ0KfQ0KDQphY3NfMjAwOV9zZiA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJy4vMS1kYXRhLzQtaW50ZXJpbS9jb28tYWNzLTIwMDktc2YucmRzJykpDQoNCg0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtMjAxNS1zZi5yZHMnKSkpew0KICAgICAgICAjIExvYWQgdGhlIHNmIG9iamVjdA0KICAgICAgICANCiAgICAgICAgY29vX2dlb21zXzIwMTVfc2YgPC0gcmVhZF9yZHMocm9vdF9maWxlKCcuLzEtZGF0YS80LWludGVyaW0vY29vLWFjcy0yMDE1LWdlb21zLXNmLnJkcycpKQ0KICAgICAgICANCiAgICAgICAgIyBEaXN0cmlidXRlIHRoZSBhY3MgaW50byBhIGRhdGFmcmFtZSwNCiAgICAgICAgIyBqb2luIGl0IHRvIHRoZSBzZiBvYmplY3QsDQogICAgICAgICMgYWRkIGFuICdFTkRZRUFSJyB2YXJpYWJsZQ0KICAgICAgICAjIHNhdmUgYXMgYW4gc2Ygb2JqZWN0DQogICAgICAgIA0KICAgICAgICBhY3NfdGliYmxlICU+JSANCiAgICAgICAgICAgICAgICBmaWx0ZXIoRU5EWUVBUiAlaW4lIDIwMTUpICU+JSANCiAgICAgICAgICAgICAgICBleHRyYWN0MignQUNTJykgJT4lIA0KICAgICAgICAgICAgICAgIG1hcChkaXN0cmlidXRlX2FjcykgJT4lIA0KICAgICAgICAgICAgICAgIHJlZHVjZShsZWZ0X2pvaW4sIGJ5ID0gYygiTkFNRSIsICJHRU9JRDYiKSkgJT4lIA0KICAgICAgICAgICAgICAgIHJlbmFtZShOQU1FX0ZVTEwgPSBOQU1FKSAlPiUgDQogICAgICAgICAgICAgICAgbGVmdF9qb2luKGNvb19nZW9tc18yMDE1X3NmLCBieSA9IGMoJ0dFT0lENicsJ05BTUVfRlVMTCcpKSAlPiUNCiAgICAgICAgICAgICAgICBtdXRhdGUoRU5EWUVBUiA9IG1hcF9pbnQoQjAzMDAyXzAwMSwgZW5keWVhciksDQogICAgICAgICAgICAgICAgICAgICAgIEdFT0dSQVBIWSA9IG1hcF9jaHIoQjAzMDAyXzAwMSwgZ2V0X2dlb2cpKSAlPiUgDQogICAgICAgICAgICAgICAgc2VsZWN0KE5BTUUsTkFNRV9GVUxMLEdFT0lENiwgU0VBQ0NEX0xHTCxFTkRZRUFSLGV2ZXJ5dGhpbmcoKSxnZW9tZXRyeSkgJT4lIA0KICAgICAgICAgICAgICAgIHN0X2FzX3NmKCkgJT4lIA0KICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJy4vMS1kYXRhLzQtaW50ZXJpbS9jb28tYWNzLTIwMTUtc2YucmRzJykpDQp9DQoNCmFjc18yMDE1X3NmIDwtIHJlYWRfcmRzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3MtMjAxNS1zZi5yZHMnKSkNCg0KDQoNCmBgYA0KDQojIyMjIENlbnN1cyBUYWJsZXMsIDIwMDUtMjAwOQ0KYGBge3IgY2Vuc3VzLXNob3ctMjAwMC10YWJsZX0NCg0KbWlzY2dpczo6cHJpbnRfcGFnZWRfc2YoYWNzXzIwMDlfc2YpDQpgYGANCg0KDQojIyMjIENlbnN1cyBUYWJsZXMsIDIwMTEtMjAxNQ0KYGBge3IgY2Vuc3VzLXNob3ctMjAxMC10YWJsZX0NCm1pc2NnaXM6OnByaW50X3BhZ2VkX3NmKGFjc18yMDE1X3NmKQ0KYGBgDQoNCiMjIyMgRGF0YSBTdHJ1Y3R1cmU6IGBhY3NgIG9iamVjdHMgZGlzdHJpYnV0ZWQgaW4gYHNmYCBvYmplY3RzDQoNCkluIHRoaXMgbWV0aG9kLCBlYWNoIHJvdyBjb250YWlucyBhIGRpZmZlcmVudCBjZW5zdXMgZ2VvZ3JhcGh5IGFuZCBlYWNoIGNvbHVtbiBjb250YWlucyBhIHNpbmdsZSBjb2x1bW4gb2YgYSBzaW5nbGUgY2Vuc3VzIHRhYmxlLiBGb3IgaW5zdGFuY2UsIGNvbHVtbiBgQjAzMDAyXzAwM2AgY29udGFpbnMgdGhlIHRoaXJkIGNvbHVtbiBvZiB0aGUgJ0hpc3BhbmljIG9yIExhdGlubywgQnkgUmFjZScgdGFibGUsIHdoaWNoIGNvbnRhaW5zIHRoZSBlc3RpbWF0ZSBvZiBwZW9wbGUgd2hvIGlkZW50aWZ5IGFzICJOb3QgSGlzcGFuaWMgb3IgTGF0aW5vOiBXaGl0ZSBhbG9uZSI6DQoNCmBgYHtyIGNlbnN1cy1leGFtcGxlLXJvd30NCmFjc18yMDA5X3NmICU+JSBzZWxlY3QoTkFNRV9GVUxMLEdFT0lENixFTkRZRUFSLEIwMzAwMl8wMDMpICU+JSBzbGljZSgzKSAlPiUgbWlzY2dpczo6cHJpbnRfcGFnZWRfc2YoKQ0KYGBgDQoNCkVhY2ggImNlbGwiIG9mIHRoZSBkYXRhZnJhbWUgY29udGFpbnMgYSBzaW5nbGUgYGFjcy1jbGFzc2Agb2JqZWN0XltNb3JlIGluZm9ybWF0aW9uIG9uIHRoZSBgYWNzLWNsYXNzYCBjYW4gYmUgZm91bmQgaW4gdGhlIGBhY3NgIHBhY2thZ2UgW2RvY3VtZW50YXRpb25dKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9hY3MvYWNzLnBkZikgYW5kIHRoZSBwYWNrYWdlIGF1dGhvcidzIFt1c2VyIGd1aWRlXShodHRwOi8vZWdsZW5uLnNjcmlwdHMubWl0LmVkdS9jaXR5c3RhdGUvd3AtY29udGVudC91cGxvYWRzLzIwMTMvMDYvd3BpZC13b3JraW5nX3dpdGhfYWNzX1IzLnBkZikuDQpdLCB3aGljaCBpdHNlbGYgY29udGFpbnMgYSBzZXQgb2YgbWV0YWRhdGEgaW5jbHVkaW5nIHRoZSBlc3RpbWF0ZSB2YWx1ZSwgc3RhbmRhcmQgZXJyb3IsIGdlb2dyYXBoaWMgaWRlbnRpZmllciwgYW5kIG90aGVyIHVzZWZ1bCBpbmZvcm1hdGlvbjogDQoNCmBgYHtyIGNlbnN1cy1leGFtcGxlLWNlbGx9DQphY3NfMjAwOV9zZiAlPiUgc2xpY2UoMykgJT4lIGV4dHJhY3QyKCdCMDMwMDJfMDAzJykgJT4lIGV4dHJhY3QyKDEpIA0KYWNzXzIwMDlfc2YgJT4lIHNsaWNlKDMpICU+JSBleHRyYWN0MignQjAzMDAyXzAwMycpICU+JSBleHRyYWN0MigxKSAlPiUgc3RyKCkgDQpgYGANCg0KU3RvcmluZyBgYWNzYCBvYmplY3RzIGluIGEgc2ltcGxlIGZlYXR1cmUgZGF0YWZyYW1lXltNb3JlIGluZm9ybWF0aW9uIG9uIHRoZSBzaW1wbGUgZmVhdHVyZXMgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TaW1wbGVfRmVhdHVyZXMpLCB3aGlsZSB0aGUgaW1wbGVtZW50YXRpb24gb2YgdGhpcyBkYXRhIHN0cnVjdHVyZSBpbiBSIGlzIGRvY3VtZW50ZWQgW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9zZi9zZi5wZGYpIGFuZCBbaGVyZV0oaHR0cHM6Ly9lZHplci5naXRodWIuaW8vc2ZyL2FydGljbGVzL3NmMS5odG1sKS5dIGlzIHVuY29udmVudGlvbmFsIGJ1dCBpdCBmb2xsb3dzIGEgZ2VuZXJhbCBwcmluY2lwbGUgb2YgY29tcHV0aW5nOiBbZG9uJ3QgcmVwZWF0IHlvdXJzZWxmIChEUlkpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Eb24lMjd0X3JlcGVhdF95b3Vyc2VsZikuIFRoZSBkYXRhZnJhbWUgc3RydWN0dXJlIGtlZXBzIHJlbGF0ZWQgYGFjc2Agb2JqZWN0cyBhbmQgZ2VvbWV0cmllcyB0b2dldGhlciwgeWllbGRpbmcgYmVuZWZpdHMgd2hlbiB0aGUgdGltZSBjb21lcyB0byBvcGVyYXRlIG9uIHRoZSBkYXRhLiANCg0KRm9yIGV4YW1wbGUsIGlmIGNlbnN1cyB0cmFjdHMgbmVlZCB0byBiZSBub3JtYWxpemVkIGJlZm9yZSB0ZW1wb3JhbCBjb21wYXJpc29uIChhcyBpcyB0aGUgY2FzZSBpbiB0aGlzIHByb2plY3QpLCB0aGF0IHByb2Nlc3MgY2FuIG9jY3VyIGluIGEgc2luZ2xlLCBjb21wcmVoZW5zaXZlIHN0ZXAgcmF0aGVyIHRoYW4gaW5kaXZpZHVhbGx5IGZvciBlYWNoIGNlbnN1cyB0YWJsZS4gVGhpcyBlZmZpY2llbmN5IGdhaW4gaXMgcGFydGljdWxhcmx5IGltcG9ydGFudCBpZiBjZW5zdXMgdGFibGVzIGFyZSBhZGRlZCBvciByZW1vdmVkLCB3aGljaCBtYXkgb2NjdXIgZmVxdWVudGx5IGluIHRoZSBleHBsb3JhdG9yeSBwaGFzZSBvZiBhbiBhbmFseXNpcy4NCg0KDQojIyMgTm9ybWFsaXplZCBwcmUtMjAxMCBEYXRhIHstfQ0KDQpVbHRpbWF0ZWx5IHRoZSBBQ1MgZGF0YSB3aWxsIGJlIGNvbWJpbmVkIGludG8gYSBzaW5nbGUgc2ltcGxlIGZlYXR1cmUgb2JqZWN0LCBidXQgYmVmb3JlIHRoYXQgY2FuIGhhcHBlbiB0aGUgcHJlLTIwMTAgbXVzdCBiZSBub3JtYWxpemVkLiBUaGUgTFREQiAyMDAwLTIwMTAgQ3Jvc3N3YWxrIGZpbGUgaXMgYSB0YWJ1bGFyIHRvb2wgdGhhdCBjbGFyaWZpZXMgd2hpY2ggdHJhY3RzIGNoYW5nZSBmcm9tIGRlY2FkZSB0byBkZWNhZGUsIHdoYXQgdHlwZSBvZiBjaGFuZ2Ugb2NjdXJyZWQgKGUuZy4sIGNvbnNvbGlkYXRpb24sIHNwbGl0LCBtYW55LXRvLW1hbnksIG5vbmUpLCBhbmQgd2hhdCB3ZWlnaHRpbmcgbWV0cmljIHNob3VsZCBiZSB1c2VkIHRvIGlucHV0ZSB0aGUgcHJlLTIwMTAgdmFsdWVzLiBUaGlzIGluZm9ybWF0aW9uIG1ha2VzIGl0IHBvc3NpYmxlIHRvIGNvbmR1Y3QgbWVhbmluZ2Z1bCB0ZW1wb3JhbCBhbmFseXNpcyBvbiB0cmFjdHMgd2hvc2UgYm91bmRhcmllcyBjaGFuZ2VkIGJldHdlZW4gdGhlIHR3byBkZWNhZGVzLiBNb3JlIGluZm9ybWF0aW9uIHJlZ2FyZGluZyB0aGUgbm9ybWFsaXphdGlvbiBtZXRob2QgY2FuIGJlIGZvdW5kIGF0IHRoZSBbTG9uZ2l0dWRpbmFsIFRyYWN0IERhdGFiYXNlIHdlYnNpdGVdKGh0dHA6Ly93d3cuczQuYnJvd24uZWR1L3VzMjAxMC9SZXNlYXJjaGVyL0xUREIuaHRtKS4NCg0KT25jZSB0aGUgcHJlLTIwMTAgZGF0YSBoYXMgYmVlbiBub3JtYWxpemVkLCB0aGUgZGF0YSBmb3IgdGhlIHR3byBvYnNlcnZhdGlvbnMgcGVyaW9kcyBjYW4gYmUgY29tYmluZWQgaW50byBhIHNpbmdsZSBkYXRhZnJhbWU6DQoNCmBgYHtyIGNlbnN1cy1ub3JtYWxpemVkfQ0KDQojIENyZWF0ZSB0aGUgY3Jvc3N3YWxrIG9iamVjdA0KDQppZighZmlsZS5leGlzdHMocm9vdF9maWxlKCcxLWRhdGEvNC1pbnRlcmltL2N3LTIwMDAtMjAxMC5yZHMnKSkpew0KICAgICAgICANCiAgICAgICAgIyBBIGZ1bmN0aW9uIGZvciBpZGVudGlmeWluZyBkdXBsaWNhdGVkIEdFT0lEcw0KICAgICAgICANCiAgICAgICAgaW5fZHVwcyA8LSBmdW5jdGlvbihkZixjb2wpZGZbW2NvbF1dICVpbiUgZGZbW2NvbF1dW2R1cGxpY2F0ZWQoZGZbW2NvbF1dKV0NCiAgICAgICAgDQogICAgICAgICMgQ3JlYXRlIHRoZSBvYmplY3QNCiAgICAgICAgIyBOb3RlOiB0aGUgbGFzdCBzdGVwIGJlZm9yZSB3cml0aW5nIHRoZSBvYmplY3QgaXMgdGhlIGNyZWF0aW9uIG9mIGEgDQogICAgICAgICMgZHVtbXkgcm93IHRoYXQgd2lsbCBhbGxvdyBub24tdHJhY3QgZ2VvbWV0cmllcyB0byBiZSBqb2luZWQgDQogICAgICAgICMgYW5kICJub3JtYWxpemVkIiAodGhleSB3aWxsIGJlIHdlaWdodGVkIGxpa2UgdGhlIHRyYWN0cyB3aG9zZSBib3VuZGFyaWVzIGRpZCBub3QgY2hhbmdlKQ0KICAgICAgICByZWFkX2NzdigNCiAgICAgICAgICAgICAgICByb290X2ZpbGUoJzEtZGF0YS8zLWV4dGVybmFsL21hbnVhbC9jcm9zc3dhbGtfMjAwMF8yMDEwLmNzdicpLA0KICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGNvbHMoY2JzYTEwID0gY29sX2NoYXJhY3RlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2NmbGFnMTAgPSBjb2xfY2hhcmFjdGVyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGFuZ2V0eXBlID0gY29sX2NoYXJhY3RlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0ZGl2MTAgPSBjb2xfY2hhcmFjdGVyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbGFjZWZwMTAgPSBjb2xfY2hhcmFjdGVyKCkpDQogICAgICAgICkgJT4lDQogICAgICAgICAgICAgICAgcmVuYW1lKEdFT0lEXzIwMDAgPSB0cnRpZDAwLA0KICAgICAgICAgICAgICAgICAgICAgICBHRU9JRF8yMDEwID0gdHJ0aWQxMCkgJT4lIA0KICAgICAgICAgICAgICAgIG11dGF0ZShLQyA9IHN0cl9zdWIoR0VPSURfMjAwMCwxLDUpKSAlPiUNCiAgICAgICAgICAgICAgICBmaWx0ZXIoS0MgPT0gJzUzMDMzJykgJT4lDQogICAgICAgICAgICAgICAgbXV0YXRlKEdFT0lENl8yMDAwID0gc3RyX3N1YihHRU9JRF8yMDAwLDYsMTEpLA0KICAgICAgICAgICAgICAgICAgICAgICBHRU9JRDZfMjAxMCA9IHN0cl9zdWIoR0VPSURfMjAxMCw2LDExKSwNCiAgICAgICAgICAgICAgICAgICAgICAgQ0hBTkdFX1RZUEUgPSBjaGFuZ2V0eXBlLA0KICAgICAgICAgICAgICAgICAgICAgICBXRUlHSFQgPSByb3VuZCh3ZWlnaHQsNSkpICU+JSANCiAgICAgICAgICAgICAgICBzZWxlY3QobWF0Y2hlcygnR0VPSUQnKSxDSEFOR0VfVFlQRSwgV0VJR0hUKSAlPiUgDQogICAgICAgICAgICAgICAgbXV0YXRlKEdFT0lENl9CT1RIID0gcGFzdGUwKEdFT0lENl8yMDAwLEdFT0lENl8yMDEwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgRFVQXzIwMTBfTEdMID0gaW5fZHVwcyguLCdHRU9JRDZfMjAxMCcpKSAlPiUgDQogICAgICAgICAgICAgICAgc2VsZWN0KG1hdGNoZXMoJ0dFT0lEJyksRFVQXzIwMTBfTEdMLGV2ZXJ5dGhpbmcoKSkgJT4lIA0KICAgICAgICAgICAgICAgIG11dGF0ZShHRU9HUkFQSFkgPSAndHJhY3QnKSAlPiUgDQogICAgICAgICAgICAgICAgYmluZF9yb3dzKA0KICAgICAgICAgICAgICAgICAgICAgICAgdGliYmxlKCdHRU9JRF8yMDAwJyA9IE5BX2NoYXJhY3Rlcl8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0dFT0lEXzIwMTAnID0gTkFfY2hhcmFjdGVyXywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnR0VPSUQ2XzIwMDAnID0gTkFfY2hhcmFjdGVyXywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnR0VPSUQ2XzIwMTAnID0gTkFfY2hhcmFjdGVyXywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnR0VPSUQ2X0JPVEgnID0gTkFfY2hhcmFjdGVyXywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRFVQXzIwMTBfTEdMJyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdDSEFOR0VfVFlQRScgPSAnMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1dFSUdIVCcgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHRU9HUkFQSFknID0gJ2NvdW50eScpDQogICAgICAgICAgICAgICAgKSAlPiUNCiAgICAgICAgICAgICAgICBiaW5kX3Jvd3MoDQogICAgICAgICAgICAgICAgICAgICAgICB0aWJibGUoJ0dFT0lEXzIwMDAnID0gTkFfY2hhcmFjdGVyXywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnR0VPSURfMjAxMCcgPSBOQV9jaGFyYWN0ZXJfLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHRU9JRDZfMjAwMCcgPSBOQV9jaGFyYWN0ZXJfLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHRU9JRDZfMjAxMCcgPSBOQV9jaGFyYWN0ZXJfLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdHRU9JRDZfQk9USCcgPSBOQV9jaGFyYWN0ZXJfLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdEVVBfMjAxMF9MR0wnID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0NIQU5HRV9UWVBFJyA9ICcxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnV0VJR0hUJyA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0dFT0dSQVBIWScgPSAnY291bnR5IHN1YmRpdmlzaW9uJykNCiAgICAgICAgICAgICAgICApICU+JQ0KICAgICAgICAgICAgICAgIHdyaXRlX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vY3ctMjAwMC0yMDEwLnJkcycpKQ0KfQ0KDQpjdyA8LSByZWFkX3Jkcyhyb290X2ZpbGUoJzEtZGF0YS80LWludGVyaW0vY3ctMjAwMC0yMDEwLnJkcycpKQ0KDQoNCm5vcm1hbGl6ZV9hY3MgPC0gZnVuY3Rpb24oYWNzXzIwMTVfc2YsIGFjc18yMDA5X3NmLCBjcm9zc3dhbGssIHRhYmxlcyl7DQogICAgICAgIA0KICAgICAgICAjIGJyb3dzZXIoKQ0KICAgICAgICANCiAgICAgICAgIyBVbnBhY2sgdGhlIGFjcyBvYmplY3QNCiAgICAgICAgDQogICAgICAgIGFjcyA8LSBhY3NfMjAxNV9zZiAlPiUgZXh0cmFjdDIoMykgJT4lIGV4dHJhY3QyKDEpDQogICAgICAgIA0KICAgICAgICAjIEdldCB0aGUgR0VPSUQ2DQogICAgICAgIA0KICAgICAgICBnZW9pZDYgPC0gYWNzICU+JSBnZW9ncmFwaHkgJT4lIGV4dHJhY3QyKCd0cmFjdCcpDQogICAgICAgIA0KICAgICAgICAjIEdldCB0aGUgTkFNRSAodGhpcyB3aWxsIGJlIHVzZWQgdG8gam9pbiBsYXRlcikNCiAgICAgICAgDQogICAgICAgIG5hbWVfZnVsbCA8LSBhY3MgJT4lIA0KICAgICAgICAgICAgICAgIGdlb2dyYXBoeSAlPiUgDQogICAgICAgICAgICAgICAgZXh0cmFjdDIoJ05BTUUnKQ0KICAgICAgICANCiAgICAgICAgDQogICAgICAgICMgR2VvIHR5cGUNCiAgICAgICAgDQogICAgICAgIGdlb2cgPC0gYWNzICU+JSANCiAgICAgICAgICAgICAgICBnZW9ncmFwaHkoKSAlPiUgDQogICAgICAgICAgICAgICAgZmxhdHRlbigpICU+JSANCiAgICAgICAgICAgICAgICBtYXAoLmYgPSB+ICFpcy5uYSgueCkpICU+JSANCiAgICAgICAgICAgICAgICByZXYgJT4lIA0KICAgICAgICAgICAgICAgIHRpYmJsZSgnR0VPRycgPSBuYW1lcyguKSwNCiAgICAgICAgICAgICAgICAgICAgICAgJ0xHTCcgPSB1bmxpc3QoLikpICU+JSANCiAgICAgICAgICAgICAgICBzZWxlY3QoR0VPRyxMR0wpICU+JSANCiAgICAgICAgICAgICAgICBmaWx0ZXIoTEdMKSAlPiUgDQogICAgICAgICAgICAgICAgc2xpY2UoMSkgJT4lIA0KICAgICAgICAgICAgICAgIGV4dHJhY3QyKCdHRU9HJykgJT4lIA0KICAgICAgICAgICAgICAgIGlmX2Vsc2UoLiAlaW4lICdjb3VudHlzdWJkaXZpc2lvbicsDQogICAgICAgICAgICAgICAgICAgICAgICAnY291bnR5IHN1YmRpdmlzaW9uJywNCiAgICAgICAgICAgICAgICAgICAgICAgIC4pDQogICAgICAgIA0KICAgICAgICAjIFN1YnNldCB0aGUgY3Jvc3N3YWxrIG9iamVjdA0KICAgICAgICANCiAgICAgICAgY3dfc2VsIDwtIGNyb3Nzd2FsayAlPiUgDQogICAgICAgICAgICAgICAgZmlsdGVyKEdFT0lENl8yMDEwICVpbiUgZ2VvaWQ2KSAlPiUgDQogICAgICAgICAgICAgICAgZmlsdGVyKEdFT0dSQVBIWSAlaW4lIGdlb2cpDQogICAgICAgIA0KICAgICAgICANCiAgICAgICAgIyBDb21iaW5lIHRoZSBjZW5zdXMgdGFibGUgY29sdW1uIG5hbWVzIGludG8gYSByZWdleCBzdHJpbmcNCiAgICAgICAgDQogICAgICAgIHRibHNfcmVnZXggPC0gcGFzdGUwKHRhYmxlcyxjb2xsYXBzZSA9ICd8JykNCiAgICAgICAgDQogICAgICAgICMgSW5uZXJfam9pbiB0byB0aGUgYWNzXzIwMDlfc2YsDQogICAgICAgICMgYXBwbHkgdGhlIHdlaWdodGluZywNCiAgICAgICAgIyBhbmQgY29tYmluZSB0aGUgcmVjb3Jkcw0KICAgICAgICANCiAgICAgICAgYWNzX3RibF8yMDA5IDwtIA0KICAgICAgICAgICAgICAgIGxlZnRfam9pbihjd19zZWwsYWNzXzIwMDlfc2YsIGJ5ID0gYygnR0VPSUQ2XzIwMDAnID0gJ0dFT0lENicsICdHRU9HUkFQSFknKSkgJT4lIA0KICAgICAgICAgICAgICAgIGdhdGhlcihUQkxfTkFNRSwgQUNTX09CSiwgbWF0Y2hlcyh0YmxzX3JlZ2V4KSkgJT4lIA0KICAgICAgICAgICAgICAgIG11dGF0ZShXRUlHSFRFRCA9IG1hcDIoQUNTX09CSixXRUlHSFQsIH4gLnggKiAueSksDQogICAgICAgICAgICAgICAgICAgICAgIFRCTF9OQU1FID0gcGFzdGUwKFRCTF9OQU1FLCdfMjAwOV9OT1JNTCcpKSAlPiUNCiAgICAgICAgICAgICAgICBncm91cF9ieShUQkxfTkFNRSkgJT4lIA0KICAgICAgICAgICAgICAgIGRvKEFDU19PQkpfQ09NQiA9IGNvbF90b19hY3MoLiRXRUlHSFRFRCkgJT4lIGFwcGx5KDEsc3VtKSkgJT4lIA0KICAgICAgICAgICAgICAgIHNwcmVhZChUQkxfTkFNRSxBQ1NfT0JKX0NPTUIpICU+JSANCiAgICAgICAgICAgICAgICBtdXRhdGUoTkFNRV9GVUxMID0gbmFtZV9mdWxsKSAlPiUgDQogICAgICAgICAgICAgICAgc2VsZWN0KE5BTUVfRlVMTCxldmVyeXRoaW5nKCkpDQogICAgICAgIA0KICAgICAgICANCiAgICAgICAgIyBhY3NfdGJsXzIwMDkgPC0gDQogICAgICAgICMgICAgICAgICBsZWZ0X2pvaW4oY3dfc2VsLGFjc18yMDA5X3NmLCBieSA9IGMoJ0dFT0lENl8yMDAwJyA9ICdHRU9JRDYnKSkgJT4lIA0KICAgICAgICAjICAgICAgICAgZ2F0aGVyKFRCTF9OQU1FLCBBQ1NfT0JKLCBtYXRjaGVzKHRibHNfcmVnZXgpKSAlPiUgDQogICAgICAgICMgICAgICAgICBtdXRhdGUoV0VJR0hURUQgPSBtYXAyKEFDU19PQkosV0VJR0hULCB+IC54ICogLnkpLA0KICAgICAgICAjICAgICAgICAgICAgICAgIFRCTF9OQU1FID0gcGFzdGUwKFRCTF9OQU1FLCdfMjAwOV9OT1JNTCcpKSAlPiUNCiAgICAgICAgIyAgICAgICAgIGdyb3VwX2J5KFRCTF9OQU1FKSAlPiUgDQogICAgICAgICMgICAgICAgICBkbyhBQ1NfT0JKX0NPTUIgPSBjb2xfdG9fYWNzKC4kV0VJR0hURUQpICU+JSBhcHBseSgxLHN1bSkpICU+JSANCiAgICAgICAgIyAgICAgICAgIHNwcmVhZChUQkxfTkFNRSxBQ1NfT0JKX0NPTUIpICU+JSANCiAgICAgICAgIyAgICAgICAgIG11dGF0ZShHRU9JRDZfMjAwOV9OT1JNTCA9IGdlb2lkNikgJT4lIA0KICAgICAgICAjICAgICAgICAgc2VsZWN0KEdFT0lENl8yMDA5X05PUk1MLGV2ZXJ5dGhpbmcoKSkNCiAgICAgICAgDQogICAgICAgIHJldHVybihhY3NfdGJsXzIwMDkpDQogICAgICAgIA0KICAgICAgICANCn0NCg0KY29sX3RvX2FjcyA8LSBmdW5jdGlvbihhY3NfdGliYmxlX2NvbCl7YWNzX3RpYmJsZV9jb2wgJT4lIHVubGlzdCh1c2UubmFtZXMgPSBGQUxTRSkgJT4lIHJlZHVjZShyYmluZC5hY3MpfQ0KDQojIEFwcGx5IHRoZSBub3JtYWxpemF0aW9uIG1ldGhvZCB0byB0aGUgcHJlLTIwMTAgZGF0YQ0KaWYoIWZpbGUuZXhpc3RzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3Mtbm9ybWwtc2YucmRzJykpKXsNCiAgICAgICAgDQphY3NfMjAxNV9zZl9yZW5hbWVkIDwtIA0KICAgICAgICBhY3NfMjAxNV9zZiAlPiUgDQogICAgICAgIGdhdGhlcihUQkxfTkFNRSwgQUNTX09CSiwgbWF0Y2hlcyhwYXN0ZTAodGFibGVzLGNvbGxhcHNlID0gJ3wnKSkpICU+JSANCiAgICAgICAgbXV0YXRlKFRCTF9OQU1FID0gcGFzdGUwKFRCTF9OQU1FLCdfMjAxNScpKSAlPiUgDQogICAgICAgIHNwcmVhZChUQkxfTkFNRSwgQUNTX09CSikgJT4lIA0KICAgICAgICBsZWZ0X2pvaW4oYWNzXzIwMTVfc2YgJT4lIHNlbGVjdChHRU9JRDYsTkFNRV9GVUxMLGdlb21ldHJ5KSwgYnkgPSBjKCdHRU9JRDYnLCdOQU1FX0ZVTEwnKSkNCg0KYWNzXzIwMTVfc2YgJT4lDQogICAgICAgIGZpbHRlcihHRU9JRDYgJSFpbiUgJzk5MDEwMCcpICU+JQ0KICAgICAgICBzZWxlY3QoLU5BTUUsLUdFT0lENiwtU0VBQ0NEX0xHTCwtRU5EWUVBUiwtZ2VvbWV0cnkpICU+JSANCiAgICAgICAgc3BsaXQoLiROQU1FX0ZVTEwpICU+JQ0KICAgICAgICBtYXAoLmYgPSBub3JtYWxpemVfYWNzLA0KICAgICAgICAgICAgYWNzXzIwMDlfc2YgPSBhY3NfMjAwOV9zZiwNCiAgICAgICAgICAgIGNyb3Nzd2FsayA9IGN3LA0KICAgICAgICAgICAgdGFibGVzID0gdGFibGVzKSAlPiUNCiAgICAgICAgcmVkdWNlKGJpbmRfcm93cykgJT4lDQogICAgICAgIGZ1bGxfam9pbihhY3NfMjAxNV9zZl9yZW5hbWVkLC4sYnkgPSAnTkFNRV9GVUxMJykgJT4lDQogICAgICAgIHNlbGVjdChOQU1FOlNFQUNDRF9MR0wsZ2VvbWV0cnksbWF0Y2hlcygnMjAxNScpLG1hdGNoZXMoJzIwMDknKSwtRU5EWUVBUikgJT4lDQogICAgICAgIGZpbHRlcihHRU9JRDYgJSFpbiUgJzk5MDEwMCcpICU+JQ0KICAgICAgICBzdF9hc19zZigpICU+JSANCiAgICAgICAgd3JpdGVfcmRzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3Mtbm9ybWwtc2YucmRzJykpDQogICAgICAgIA0KDQoNCn0NCg0KYWNzX25vcm1sX3NmIDwtIA0KICAgICAgICAgICAgICAgIHJlYWRfcmRzKHJvb3RfZmlsZSgnLi8xLWRhdGEvNC1pbnRlcmltL2Nvby1hY3Mtbm9ybWwtc2YucmRzJykpICU+JSANCiAgICAgICAgICAgICAgICBzZWxlY3QoTkFNRTpTRUFDQ0RfTEdMLGdlb21ldHJ5LG1hdGNoZXMoJzIwMTUnKSxtYXRjaGVzKCcyMDA5JykpDQogICAgICAgICAgICAgICAgDQoNCg0KbWlzY2dpczo6cHJpbnRfcGFnZWRfc2YoYWNzX25vcm1sX3NmKQ0KYGBgDQoNCg0K